#coding:utf8

from pynput import keyboard
import time
from pynput import mouse
import threading
import math
from help import * 
import sys, os, random

#config

#isOn2如果是false，鼠标点击后不开启显示模式；是true，点击后开启显示模式。
isOn2 = False

#微调角度速率配置，可添加
is_working = False
sca_l = [1, 0.3]
if is_working:
    sca_l = [1, 0.3, 0.1]
max_zi = 60 #最多数字坐标个数
if is_working:
    max_zi = 60    
max_l = 2000 #最大数字坐标长度
if is_working:
    max_l = 2000    
main_win_size =  (50, 24)  #提示窗口大小，高度是25时，文字显示会上下动。
if is_working:
    main_win_size =  (50, 26)
    
mouse_input = False #鼠标按键，当作数字键盘输入
cir_para = [17, 20, 3, 1]
if is_working:
    cir_para = [18, 23, 3, 1]
du_refresh_interval = 0.05
def get_scroll_sca():
    if to<600:
        return 200
    if to<1000:
        return 250
    return 300    
change_win_color = False
mouse_speed_take1 = 0.05
mouse_speed_take2 = 0.1
def mouse_moving_check():
    if len(mouse_moving_type) < 2:
        return -1
    if mouse_moving_type[0] < 100 and  mouse_moving_type[1] < 150:
        return 0
    return 1


lock_l = [1, 10, 50] #单步移动模式速度，可添加。第一个固定为1
lock_step_default = 1 #默认移动速度，是上面列表的位置序号
small_win = True #为true，则每个数字坐标一个窗口。否则使用全屏窗口
enter_gap = 50

listen_mouse_click = True #监听鼠标按键，当作数字键盘输入
# small_win为false时，全屏窗口的大小和位置
geo_x = -100
geo_y = -100
geo_x_end = 1366
geo_y_end = 768

min_d = 25 #数字坐标间最小距离
min_d_mouse = 30 #数字坐标距离鼠标箭头最小距离
min_d_mouse_disapp = 25 
icon_file_path = 'aero_ns_xl.cur' #如果运行目录下有此icon文件，会显示系统托盘
sum_max_l = 6 #倍数数字最大长度
draw_txt_yAdd = 10 # 画数字坐标时，文字上下偏移
draw_txt_txtSize = 16  #数字坐标数字大小
draw_txt_pathSize = 6   #数字坐标边缘大小
draw_cir_out_width = 3 #圆圈外圈宽度
draw_cir_out_rad = 8 #圆圈外圈半径
draw_cir_in_width = 3 #圆圈内圈宽度
draw_cir_in_rad = 7 #圆圈内圈半径
txt_win_size = (60, 30) #数字坐标窗口大小
txt_gap = 10  #数字坐标在窗口中的偏移
cir_win_size = (60, 30) #圆圈窗口大小
cir_gap = 10 #圆圈在窗口中的偏移

main_win_border = 1 # 提示窗口边框大小
main_win_txt_size = 10 #提示窗口文字大小
small_win_trans = True #数字坐标窗口和圆圈窗口是否透明，试验大小时可以改成false
pos_json_path = 'pos.json' #点位坐标文件路径


always_show_one = True
show_one_delay = 0.35

reset_show_one = False
mouse_delay = 0.3
two_mouse_check_interval = 0.4
put_speed_interval = 0.02
speed_q_len = 7

suo_di  = 30
#其他显示元素，在代码中对于位置修改
#config end


force_show = False
fix_pos = (0, 0)  #起始位置
isShow = False #是否显示
sum = '0' #倍数
move_task = None #sum不为0，移动鼠标，产生移动任务
last_move_time = 0  #上次鼠标移动的时间。检测鼠标移动停顿，再执行移动任务。
click_time = -1 #点击任务
set_fix_time = 0 #移动后，设置起始位置，并设置此时间。用来处理移动出屏幕范围的情况。
is_pressed = False  #左键是否按下
last_mouse_pos = (0, 0)  #键盘操作时鼠标的位置。移动任务需要。
ctrl_pressed = False  # ctrl键按下
alt_pressed= False  #alt键按下
lock = False #数字键盘用来单步移动。

lock_step = lock_step_default #单步移动的速度。
sca = 0  #微调角度的比例
sca_du = 0 #微调角度上次剩余的度数
sca_cur = 0 #微调角度固定点的度数
sca_cur_pos = (0, 0) #微调角度固定点的位置
pause_press_time = 0 #pause键按下的时间，用来判断双击
pause_key = True #pause按下变换此值，用来隐藏窗口。
pause_move = None #双击pause键，产生移动任务
ctrl_l_time = 0 #左ctrl按下时间，用来判断双击。
pause_pressed = False # pause 按住
pause_pressed_then_other = False  #pause按住组合键
from collections import deque

def get_cur_pos():
    a = mouse.Controller().position
    if type(a) != type((0, 0)):
        return fix_pos
    if len(a) != 2:
        return fix_pos
    return a


real_mouse_time = 0
mouse_is_moving = False
mouse_moving_start_time = 0
mouse_moving_start_pos = (0, 0)
mouse_moving_type = []
mouse_moving_last_is_fast = False
mouse_moving_has_two_mosue = False
last_mouse_moving_has_two_mosue = False

is_suo = False
suo_dis = 0
suo_to = 0

to_change_time = 0
last_ge = 0
def cut_to(d):    
    if d > max_l:
        d =  max_l
    if d < 0:
        d = 0
    return d
to_lock = threading.Lock()

x2_pressed = False
x2_pressed_then_other =False
def on_move(x,y):
    global sum, move_task, isShow, last_move_time, real_mouse_time
    global  is_suo, suo_dis, suo_to, to,enter_pressed_then_other
    global to_change_time,force_show,show_one_on,x2_pressed_then_other

    if (ctrl_pressed or enter_pressed or x2_pressed) and not is_suo:
        enter_pressed_then_other = True
        x2_pressed_then_other = True
        is_suo = True
        suo_dis = max(1, cal_dis(get_cur_pos() , fix_pos))
        suo_to = to

    if (ctrl_pressed or enter_pressed or x2_pressed ) and is_suo:
        enter_pressed_then_other = True
        x2_pressed_then_other = True
        if x2_pressed and not w2.isshowing:
            show_one_on = True
            force_show = True

        d =  cal_dis(get_cur_pos(),fix_pos)- suo_dis
        to_lock.acquire()
        if d >= 0:
            to = cut_to(suo_to + d * suo_di)            
        else:
            to = suo_to * cal_dis(get_cur_pos(),fix_pos) / suo_dis
        print('suo', d)
        to_change_time = time.time()
        to_lock.release()
        
    last_move_time = time.time()
    if sum != '0':
        x, y = getp(last_mouse_pos)
        sx, sy = fix_pos
        dx = x - sx
        dy = y - sy
        dx = round(dx*float(sum)) + dx
        dy = round(dy*float(sum)) + dy
        move_task = (sx + dx - last_mouse_pos[0], sy + dy - last_mouse_pos[1])
        print('move_task', move_task)
        isShow = False
        clear(False)

def cal_dis(pos, sp):
    dx = pos[0] - sp[0]
    dy = pos[1] - sp[1]
    return math.sqrt(dx*dx+dy*dy)

def cal_mouse_d(sp):
    pos = get_cur_pos()
    dx = pos[0] - sp[0]
    dy = pos[1] - sp[1]
    return math.sqrt(dx*dx+dy*dy)

def cal_move():
    global  mouse_moving_start_time, mouse_is_moving, mouse_moving_start_pos, mouse_moving_type
    global  mouse_moving_last_is_fast, mouse_moving_has_two_mosue
    if time.time() - last_move_time > mouse_delay:
        if not mouse_is_moving:
            return
        if time.time() -mouse_moving_start_time > two_mouse_check_interval + 0.1:
            print('stop move')
            mouse_is_moving = False
            if mouse_moving_check() != 1:
                mouse_moving_last_is_fast = False
            else:
                mouse_moving_last_is_fast = True
            mouse_moving_type = []
            return
    
    if not mouse_is_moving:
        print('start move')
        mouse_is_moving = True
        mouse_moving_type = []
        if force_show or time.time() - key_input_time < 0.02:
            mouse_moving_type = [0, 0]
        mouse_moving_start_time = time.time()
        mouse_moving_start_pos = get_cur_pos()
        mouse_moving_has_two_mosue = False
    
    if time.time() - mouse_moving_start_time < two_mouse_check_interval and not mouse_moving_has_two_mosue:
        thrLock.acquire()
        ss = set()
        for i in mouse_q:
            t, h = i
            if t >= mouse_moving_start_time:
                ss.add(h)
        thrLock.release()
        
        if len(ss) >= 2:
            mouse_moving_has_two_mosue = True
    
    if time.time() - mouse_moving_start_time > mouse_speed_take1 and len(mouse_moving_type) == 0:
        mouse_moving_type.append(cal_mouse_d(mouse_moving_start_pos))        
        print('sudu', mouse_moving_type)
    if time.time() - mouse_moving_start_time > mouse_speed_take2 and len(mouse_moving_type) == 1:
        mouse_moving_type.append(cal_mouse_d(mouse_moving_start_pos))
        print('sudu', mouse_moving_type)        
        
from collections import deque

put_pos_time = 0
def deal_reset_one():
    global show_one_on
    if always_show_one:
        if reset_show_one:
            show_one_on = False
        else:
            show_one_on = True    
def moveF():
    global move_task, fix_pos, click_time, set_fix_time, show_one_on
    global  put_pos_time
    while True:
        time.sleep(0.01)            
        cal_move()
        if time.time() - set_fix_time < 0.02:
            if get_cur_pos() != fix_pos:
                print('diff', time.time() - set_fix_time, get_cur_pos(), fix_pos)
                fix_pos = get_cur_pos()
            
        if time.time() - click_time > 0.2 and click_time >= 0:
            click_time = -1
            mouse.Controller().click(mouse.Button.left)
            
        if time.time() - last_move_time > 0.1 and move_task != None:
            dx, dy = move_task
            move_task = None
            x, y = get_cur_pos()
            fix_pos = (x + dx, y + dy)
            set_fix_time = time.time()
            try:
                mouse.Controller().move(dx, dy)
                deal_reset_one()
            except Exception as e:
                print(e)            
        


mouse_pressed = False
def on_click2(x, y, button, pressed,deal_x):
    global fix_pos, isShow, mouse_pressed, show_one_on
    global x2_pressed,x2_pressed_then_other,is_suo
    print('click', button,pressed)

    if (mouse_input or deal_x) and ('x1' in str(button) or 'x2' in str(button)):
        if pressed:
            if not x2_pressed:
                x2_pressed = True
                x2_pressed_then_other = False
        if not pressed:
            x2_pressed =False
            if not x2_pressed_then_other:
                if 'x1' in str(button):
                    xing()
                if 'x2' in str(button):
                    deal_add()
            else:
                is_suo =False

        return
    if ('x1' in str(button) or 'x2' in str(button)):
        return
    
    if mouse_pressed and pressed:
        return
    if pressed:
        mouse_pressed = True
    else:
        mouse_pressed = False
    if isOn2:
        isShow = True
    else:
        isShow = False
    if always_show_one:      
        show_one_on = True
    else:
        show_one_on = False
    clear(True)

    
def on_click(x, y, button, pressed):
    on_click2(x, y, button, pressed,False)

def clear_sca():
    global sca, sca_du,sca_cur, sca_cur_pos
    sca = 0
    sca_du = 0
    sca_cur = 0
    
def clear(pos, clearLock=True):
    global  sum,  fix_pos , show_one_on, force_show, to, force_scroll,last_ge
    w2.last_ge = 0
    w2.last_to = 0
    w2.last_zi_ge = 0
    last_ge = 0
    
    to = 0
    force_scroll = False
    sum = '0'

    clear_sca()
    force_show = False
    if clearLock:
        clear_lock()
    if pos:
        fix_pos = get_cur_pos()

def getdu(mouse_pos=None):
    x, y = get_cur_pos()
    if mouse_pos:
        x, y = mouse_pos
    sx, sy = fix_pos
    dx = x - sx
    dy = y - sy
    du0 = math.atan2(dy, dx)
    s = sca_l[sca%len(sca_l)]
    d =  du0 -sca_cur
    if d >  math.pi:
        d -= 2 * math.pi
    if d < - math.pi:
        d += 2 * math.pi
    du = sca_du + d * s
    ll = math.sqrt(dx*dx+dy*dy)
    return du, ll

def getp(mouse_pos=None):
    du, ll = getdu(mouse_pos)
    sx, sy = fix_pos
    return round(ll * math.cos(du) + sx), round(ll * math.sin(du) + sy)

def is_sca():
    return sca != 0 or  sca_du != 0 or  sca_cur != 0    
    
def update_du(add):
    global sca, sca_du, sum, sca_cur, sca_cur_pos
    du, ll = getdu()
    sca_du = du
    if add:
        sca += 1
    x, y = get_cur_pos()
    sx, sy = fix_pos
    dx = x - sx
    dy = y - sy
    sca_cur = math.atan2(dy, dx)
    sca_cur_pos = (x, y)

xing_dis = 100
def xing():
    global show_one_on, isShow, force_show, sum, to, force_scroll,to_change_time,last_ge
    if sum != '0':
        if '0.0' in sum:
            force_scroll = not force_scroll
            return
        if '0.' in sum:
            d = -int(sum.replace('0.', '') )
        else:
            d = int(sum)
        to_lock.acquire()        
        to = cut_to(to+d*xing_dis)
        to_change_time = time.time()
        to_lock.release()
        sum = '0'
        return
    
    isShow = False
    ori = force_show
    clear(True)
    if w2.isshowing:
        show_one_on = False
        return
    
    if not show_one_on:
        show_one_on = True
        force_show = True
        return
    if ori:
        show_one_on = False
        force_show = False
        return
    force_show = True
    
def deal_e(pos_check = True):
    print('deal_e')
    global sum, fix_pos, isOn2, is_pressed, isShow, set_fix_time, show_one_on
    x, y = getp()
    sx, sy = fix_pos
    dx = x - sx
    dy = y - sy
    dx = round(dx*float(sum)) + dx
    dy = round(dy*float(sum)) + dy
    fix_pos =  (sx + dx, sy + dy)
    if pos_check:
        set_fix_time = time.time()
    if str(sum) != '0':
        isShow = False
    else:
        isShow = True
    clear(False)
    mouse.Controller().position = (sx + dx, sy + dy)
    deal_reset_one()     

def replay(re):
    lock_step_clear()
    last = ''
    for i in re:
        if last == '.' and i == '0':
            i = '.'
        if i == '.':
            a = 10
        else:
            a = int(i)
        deal_lock(a)
        last = i
    lock_step_clear()
    
def lock_add():
    global lock_step
    lock_step = min(lock_step + 1, len(lock_l) -1) 
    
def lock_min():
    global lock_step
    if lock_step == 0:
        #lock_step_clear()
        dotdot()
        return
    lock_step = max(0, lock_step - 1)
    
def lock_get():
    return lock_l[lock_step%len(lock_l)]
   
def lock_step_clear():
    global lock_step
    lock_step = lock_step_default
    
def clear_lock():
    global lock, lock_step
    lock = False
    lock_step_clear()

def deal_lock(a):
    global lock_step
    print('lock', a)    
    if a == 10:
        lock_min()
    if a == 5:
        lock_add()
    if a == 0:
        lock_step_clear()
    if a in arrm:
        dx, dy = arrm[a]
        mouse.Controller().move(dx*lock_get(), dy*lock_get())
        
move_to_win = False
show_one_onetime = False
def dotdot():
    global isShow, show_one_on, show_one_onetime
    if isShow:
        isShow = False                
        show_one_on = False
        return
    
    if w2.isshowing:        
        show_one_on = False
        return
    
    show_one_on = True
    show_one_onetime = True
def deal_add():
    global isShow, show_one_on, to,last_ge
    w2.last_ge = 0
    w2.last_to = 0
    w2.last_zi_ge = 0
    last_ge = 0
    to = 0
    if sum == '0':
        if isShow:
            isShow = False
            show_one_on = True
        else:
            isShow = True        
        return
    deal_e()
    
def on_press2(key):
    global sum, fix_pos, isOn2, is_pressed, isShow, lock, pause_key
    global sca, sca_du, sca_cur, click_time, show_one_on
    a = decode(key, False) 
    if a >= 0 and a <= 10:
        if a == 10 and sum[-1] == '.':
            sum = sum[:-1]
            if len(sum) == 1:
                a = int(sum)
                if a >= 1 and a <= 9:
                    deal_enter_pressed('', a)
                    return                
            dotdot()
            return
            
        if a == 0 and sum == '0':
            if is_sca():
                if get_cur_pos() == sca_cur_pos:
                    clear_sca()
                    return 
                update_du(False)
                return 
            clear(True)
            return 
        
        sum = deal_sum(sum, a, sum_max_l)
        print('update sum', sum)
        
    if a == 14:
        if sum != '0':
            sum = '0'
            return
        update_du(True)
        
    if a == 16:
        lock = not lock
        if sum != '0' and lock:
            re = sum
            sum = '0'
            replay(re)
            lock = False
          
    if a == 12: # -
        if sum != '0':
            deal_e()
            click_time = time.time()
            return
        mouse.Controller().click(mouse.Button.left)            
            
    if a == 13: #*
        xing()            
                
    if a == 11: # +
        deal_add()
        

enter_pressed = False
enter_pressed_then_other = False
def set_key_sign(key, a):
    global pause_pressed, pause_pressed_then_other, ctrl_pressed, alt_pressed
    global  enter_pressed, enter_pressed_then_other
    st = str(key)
    if 'ctrl' in st and not   ctrl_pressed:
        ctrl_pressed = True

    if 'alt' in st and not alt_pressed:
        alt_pressed = True
    if 'pause' in st:
        if not pause_pressed:
            pause_pressed = True
            pause_pressed_then_other = False
        else:
            pause_pressed_then_other = True
    if a == 15:
        if not enter_pressed:
            enter_pressed = True
            enter_pressed_then_other = False
        else:
            enter_pressed_then_other = True

cmd_mode =False            
def deal_ctrl_pressed(st, a):
    global lock, cmd_mode
    if a >= 0 and a <= 10:
        deal_lock(a)
        if alt_pressed:
            lock = True
        return
    if a == 15:
        cmd_mode = True
        
def deal_pause_pressed(st, a):
    global  move_to_win, pause_move
    if 'caps_lock' in st:
        pause_move = get_cur_pos()
        return
    
    if ((a >= 0 and a <= 10) or a in (13, 14, 16)):
        if a == 16:
            a = 10
        if a == 14:
            a = 2
        if a == 13:
            a = 6
        deal_lock(a)
        return
    if a == 12:
        mouse.Controller().click(mouse.Button.right, 1)
        return
    if a == 11:
        mouse.Controller().click(mouse.Button.middle, 1)
        return
    if a == 15:
        move_to_win = True
    
def deal_pressed():
    global is_pressed
    if not is_pressed:
        mouse.Controller().press(mouse.Button.left)  
        is_pressed = True
    else:
        mouse.Controller().release(mouse.Button.left)
        is_pressed = False
        
set_mode = False
pos_m = {}
def move_p(a):
    global fix_pos, show_one_on
    a = str(a)
    print('move', a, pos_m)
    if type(pos_m) ==type({}) and a in pos_m:
        clear(False, False)
        fix_pos =  pos_m[a]    
        mouse.Controller().position = pos_m[a]
        deal_reset_one()  

def deal_cmd(st, a):
    global set_mode, isOn2, reset_show_one, show_mouse_tip
    if a < 0:
        return False
    if a == 11:
        isOn2 = not isOn2
        return False
    
    if a == 12:
        reset_show_one = not reset_show_one
        return False
    
    if a == 13:
        show_mouse_tip = not show_mouse_tip
        return False
    if a == 14:
        global left_mouse,right_mouse
        left_mouse = []
        right_mouse = []
        print('clear mouse')
        return False
    
    if a == 16:
        set_mode = True
        return False
    
    if a >= 0 and a <= 10:
        move_p(a)
        return False
    
    return False

def load_pos():
    global pos_m
    try:
        f = open(pos_json_path)
        pos_m = json.load(f)
        f.close()        
    except:
        pos_m = {}

def add_p(a):
    global pos_m
    a = str(a)
    load_pos()
    pos_m[a] = mouse.Controller().position
    print('pos', pos_m)
    try:
        f = open(pos_json_path, 'w')
        json.dump(pos_m, f, indent=4)
        f.close()        
    except Exception as e:
        print(e)
        
    print('add', a)    

def deal_set(st, a):
    global set_mode
    if a < 0:
        return False
    
    if a >= 0 and a <= 10:
        add_p(a)
        return False
    
    return False            
def deal_enter_pressed(st, a):
    global isShow, fix_pos, cmd_mode, always_show_one
    if a == 0:
        isShow = False
        clear(True)
        return
       
    if a == 10:
        always_show_one = not always_show_one
        return
    
    use_pos = False
    if sum != '0':
        deal_e(False)
        use_pos = True        
        
    if a == 5:
        cmd_mode = True
        return
    
    if a not in arrm:
        return
    dx, dy = arrm[a]    
    dx = -dx * enter_gap
    dy = -dy * enter_gap
    print('enter', st, a)
    clear(False, False)
    if use_pos:
        p = fix_pos
    else:
        p = get_cur_pos()
    fix_pos = (p[0] + dx, p[1] + dy)
    isShow = True
key_input_time = 0    
def on_press(key):
    global last_mouse_pos, pause_pressed_then_other, cmd_mode, set_mode, key_input_time
    global enter_pressed_then_other
    key_input_time = time.time()
    st = str(key)
    a = decode(key, True)
    #print('press', st, a, time.time())
    if a == -2:
        return
    set_key_sign(key, a)
    
    if cmd_mode:
        enter_pressed_then_other = True
        cmd_mode = deal_cmd(st, a)
        print('cmd', cmd_mode)
        return
    
    if set_mode:
        set_mode = deal_set(st, a)
        enter_pressed_then_other = True
        print('set', set_mode)
        return
    
    if ctrl_pressed:
        deal_ctrl_pressed(st, a)
        enter_pressed_then_other = True
        return
    
    if pause_pressed and 'pause' not in st:
        deal_pause_pressed(st, a)
        pause_pressed_then_other = True
        enter_pressed_then_other = True
        return
    
    if enter_pressed and a != 15:
        enter_pressed_then_other = True
        deal_enter_pressed(st, a)
        return
    
    if 'scroll' in st:
        mouse.Controller().click(mouse.Button.left, 2)
        
    if 'caps_lock' in st:
        deal_pressed()
                           
    
    if lock and a >= 0 and a <= 10:
        deal_lock(a)
        return

    on_press2(key)
    last_mouse_pos = get_cur_pos()

def on_release(key):
    global ctrl_pressed, ctrl_l_time, alt_pressed, sum, pause_pressed, pause_move, pause_press_time
    global  pause_key, enter_pressed, key_input_time, cmd_mode, is_suo
    key_input_time = time.time()
    st = str(key)
    a = decode(key, False)
    print('release', st, a, time.time())
    if a ==15 :
        enter_pressed = False
        is_suo = False
        if enter_pressed_then_other:
            return
        
        if lock:
            cmd_mode = True
            return        
        deal_e()
        
    if 'pause' in st :
        pause_pressed = False
        if pause_pressed_then_other:
            return

        if  time.time() - pause_press_time  < 1:
            pause_key = not pause_key
            pause_press_time = 0
            return
        pause_press_time = time.time()            
        
    if 'ctrl_l' in st:
        if time.time() - ctrl_l_time < 0.2:
            xing()
        ctrl_l_time = time.time()
        
    if 'ctrl' in st :
        ctrl_pressed = False
        is_suo = False
    if 'alt' in st :
        alt_pressed = False
        

show_one_on = always_show_one
show_mouse_tip = True

to_lap = 0.3
class my77(QMainWindow):
    def __init__(self):
        super().__init__()                     
        self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint|Qt.ToolTip)                          
        self.setAttribute(Qt.WA_TranslucentBackground)
        if not small_win:
            self.setGeometry(geo_x, geo_y, geo_x_end-geo_x, geo_y_end-geo_y)
        else:
            self.setGeometry(geo_x, geo_y, 0, 0)
            self.hide()
            
        self.show()
        self.co = 0
        self.co2 = 0
        t = QTimer(self)
        t.timeout.connect(self.ont)
        t.start(20)
        self.last = None
        self.zl = []
        self.showl = set()
        self.show_one_time = 0
        self.one_pos = (0, 0)
        self.isshowing = False            
        self.cir = wcir(False, True)
        self.cirsign = (0, )
        self.lastxy = (0, 0)
        self.lastRefreshTime = 0
        self.lastRefreshTimeDu = 0
        self.to_is_changing = False
        self.last_ge = 0
        self.last_to = 0
        self.last_zi_ge = 0    
        if small_win:
            self.fix_c = wcir(False)
            self.sca_c = wcir(True)
            for i in range(max_zi):
                self.zl.append(wzi())

    def needRet(self):
        global      show_one_on, show_one_onetime
        if show_one_onetime:
            show_one_onetime = False
            return False
        
        if is_sca():
            return False
        
        if cal_mouse_d(fix_pos) == 0:
            return False
        if show_one_onetime:
            show_one_onetime = False
            return False
        
        if self.isshowing:            
            return
        
        if not mouse_is_moving:
            if not mouse_moving_last_is_fast and self.isshowing:
                return False
            return True
        
        if mouse_moving_check() == -1:
            return True
        
        if mouse_moving_check() == 0:
            if self.isshowing or force_show:
                return False
            
            if mouse_moving_has_two_mosue and not mouse_pressed:
                return False
            
            if time.time() - mouse_moving_start_time > two_mouse_check_interval and not self.isshowing:
                show_one_on = False
                return False
            return True
                
        if cal_mouse_d(self.one_pos) < min_d_mouse_disapp or  not self.isshowing:
            show_one_on = False
            return False

        return True
        
    def draw_cir(self):
        x,y =  get_cur_pos()
        s = (isShow, show_one_on, w2.isshowing, show_mouse_tip, x, y, force_show, show_one_onetime)
        if self.cirsign == s:
            return
        self.cirsign = s
        if (isShow or show_one_on) and w2.isshowing and show_mouse_tip:
            self.cir.draw(x+cir_para[0]-15, y+cir_para[1]+4)
            if self.cir.f != force_show:
                self.cir.f = force_show
                self.cir.update()

        elif not isShow and show_one_on and not w2.isshowing and show_mouse_tip and not show_one_onetime:            
            self.cir.draw(x+cir_para[0], y+cir_para[1])
            if self.cir.f != force_show:
                self.cir.f = force_show
                self.cir.update()
        else:
            self.cir.hide()
    def cal_to(self):
        if time.time()-to_change_time>to_lap:
            if self.to_is_changing:
                self.to_is_changing = False
                self.last_to = to
                self.last_ge = last_ge
            if last_ge>self.last_ge and ( (not is_sca() and self.last_zi_ge>1) or  ( is_sca() and self.last_zi_ge>2)):
                self.last_ge = last_ge
            return
        if not self.to_is_changing:
            self.to_is_changing = True

    def ont(self):
        self.cal_to()
        self.draw_cir()
        global  show_one_on, force_show
        cur = (0, 0)
        if isShow or show_one_on:
            cur = get_cur_pos()
        
        sign =  (isShow, fix_pos, cur, sum,sca, sca_du, sca_cur, sca_cur_pos, show_one_on, to)
        if self.last == sign and not show_one_onetime and time.time() - to_time > 0.5:
            return
        
        self.co2 += 1
        if self.needRet() and not isShow and show_one_on:
            return
                    
            
        if self.co2 % 100 == 0:
            print('co2', self.co2)
        self.last = sign
        self.showl = []
        self.fix_c_show = False
        self.sca_c_show = False       
            
        self.paintEvent2(1)
        if not self.fix_c_show:
            self.fix_c.hide()
        if not self.sca_c_show:
            self.sca_c.hide()
        self.isshowing = False
        for i in range(max_zi):
            if i >= len(self.showl):
                self.zl[i].hide()
            else:
                zi, x, y = self.showl[i]
                self.isshowing = True
                force_show = False
                if not isShow and show_one_on:
                    self.zl[i].draw(zi, x, y, True)
                    self.one_pos = (x, y)
                else:
                    self.zl[i].draw(zi, x, y, False)              
        
    def get_xy(self):
        global to_time
        if not mouse_is_moving:
            to_time = 0
            
        if isShow or  time.time() - to_time > 0.3:
            x, y = getp()
            self.lastRefreshTime = time.time()            
            return x, y
        
        if  time.time() - self.lastRefreshTime < 0.4:
            x,y = getp()            
            x2, y2=  self.lastxy
            if time.time() - self.lastRefreshTimeDu<du_refresh_interval:
                return x2,y2
            
            self.lastRefreshTimeDu = time.time()
            d1 = cal_dis(fix_pos,(x,y))
            d2 = cal_dis(fix_pos,(x2,y2))
            if d2==0:
                return x2,y2
            du = math.atan2(y-fix_pos[1],x-fix_pos[0])
            return(round(fix_pos[0]+math.cos(du)*d2) ,round(fix_pos[1]+math.sin(du)*d2) )
            
          
        x, y = getp()
        self.lastRefreshTime = time.time()
        return x, y                                
                
    def paintEvent2(self,e):
        global  to_time,to
        if not isShow and not show_one_on:
            return
        
        self.co += 1
        if self.co % 300 == 0:
            print('paintEvent1',self.co,time.monotonic())
            
        x, y = self.get_xy()
        self.lastxy = (x, y)
        sx, sy = fix_pos
        dx = x - sx 
        dy = y - sy
        ll = math.sqrt(dx*dx+dy*dy)
        
        if dx == 0 and dy == 0:
            return

        step = max(1, math.ceil(min_d / ll))
        st = step
        min_idx = step
        for i in range(step,max_l, step):
            if i * ll > min_d_mouse:
                min_idx = i
                break
            
        if not isShow:
            st = min_idx
       

        if is_sca():
            rr = [0] + list(range(st, max_l, step))
        else:
            rr =  range(st, max_l, step)

        max_ll = 0
        to_lock.acquire()

        for i in rr:            
            zx = dx * i + x
            zy = dy * i + y
            if i == min_idx and len(self.showl) > 0:
                a =  self.showl[0]
                self.showl.append(a)
                self.showl[0] =  (str(i), zx, zy)                
            else:
                self.showl.append((str(i), zx, zy))
            max_ll = max(max_ll,i)
            global last_ge
            gg = max_zi
            if not isShow:
                gg = 1
                if is_sca():
                    gg = 2
                
            if len(self.showl) >= max_zi:
                break
            if not isShow:
                if self.to_is_changing:
                    if len(self.showl)>=gg and i*ll>to:
                        break
                else:
                    if len(self.showl)>=gg and max_ll>=self.last_ge and i*ll>self.last_to:
                        break

            else:
                if len(self.showl)>=gg:
                    break

            if i * ll > max_l:
                break
        if not self.to_is_changing:
            to = max_ll*ll
        to_lock.release()
        last_ge = max_ll
        self.last_zi_ge = len(self.showl)

        if not is_sca():
            return
        self.sca_c_show = True
        self.fix_c_show = True
       
        self.fix_c.draw(sx, sy)
        self.sca_c.draw(sca_cur_pos[0], sca_cur_pos[1])
            
class wzi(QMainWindow):
    def __init__(self):
        super().__init__()                     
        self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint|Qt.ToolTip)
        if small_win_trans:
            self.setAttribute(Qt.WA_TranslucentBackground)
        self.setGeometry(0, 0, txt_win_size[0], txt_win_size[1])
        self.zi = ''
        self.isone = False
        
    def draw(self, zi, x, y, isone):
        update = False
        if self.zi != zi or self.isone != isone: 
            update = True
            self.zi = zi
            self.isone = isone
            
        if update:
            self.repaint()
        self.move(x-txt_gap, y-txt_gap)
        self.show()
        if update:
            self.repaint()        

    def paintEvent(self,e):
        p = QPainter (self);
        draw_txt(p, self.zi, txt_gap, txt_gap, draw_txt_yAdd, draw_txt_txtSize, draw_txt_pathSize, self.isone)
        
class wcir(QMainWindow):
    def __init__(self, isR, istop=False):
        super().__init__()                     
        self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint|Qt.ToolTip)
        if small_win_trans:
            self.setAttribute(Qt.WA_TranslucentBackground)
        self.setGeometry(0, 0, cir_win_size[0], cir_win_size[1])
        self.isR = isR
        self.istop = istop
        self.f = False
        
    def draw(self, x, y):
        self.move(x-cir_gap, y-cir_gap)
        self.show()    

    def paintEvent(self,e):
        p = QPainter (self);
        if not self.istop:
            drawCir(p, cir_gap, cir_gap, self.isR,draw_cir_out_width, draw_cir_out_rad, draw_cir_in_width, draw_cir_in_rad)
            return
        
        re = QRegion(0 , 0, cir_gap*2+5,cir_gap*2+5, QRegion.Ellipse);
        self.setMask(re)                 
        pen = QPen()
        qb = QBrush()
        qb.setColor(Qt.black)
        
            
        qb.setStyle(Qt.SolidPattern)        
        pen.setColor(Qt.white)
       
            
        pen.setWidth(cir_para[3])    
        p.setPen(pen)
        p.setBrush(qb)
        w =  cir_para[2]
        if not self.f:
            p.drawEllipse(QPoint(cir_gap,cir_gap),w,w)
        else:            
            p.drawRect(cir_gap-w, cir_gap-w, w*2, w*2) 


class my3(QWidget):
    def __init__(self):
        super().__init__()                                            
        self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint|Qt.ToolTip)
        self.setGeometry (100, 100, main_win_size[0], main_win_size[1])
        self.l = QLabel(self)
        self.setIni()
        h = QHBoxLayout(self)
        self.l.setStyleSheet("QLabel {border: %spx solid rgb(0, 0, 0); background-color : white;  }" % main_win_border);
        #self.setStyleSheet("QWidget { background-color : white; }");
        h.addWidget(self.l)
        d = 0
        h.setContentsMargins(d, d, d, d)
        self.setLayout(h)
        self.co = 0
        t = QTimer(self)
        t.timeout.connect(self.ont)
        t.start(20)
        self.last = None
        self.offset = None
        self.p = True
        self.t = ''        
        
        if os.path.exists(icon_file_path):
            self.tray = QSystemTrayIcon(self)
            self.tray.activated.connect(self.trayA)
            self.tray.setToolTip('mm')
            self.tray.setIcon(QIcon(icon_file_path))
            self.tray.show()
            
        
    def trayA(self,a): 
        if a == self.tray.Trigger:
            global pause_key
            pause_key = not pause_key
            
        if a == self.tray.Context:
            sys.exit(0)
            
    def closeEvent(self, a0):
        print('close')
        import sys
        sys.exit(0)
    def setIni(self):
        self.resize(main_win_size[0], main_win_size[1]) 
        self.show()
        
    def mouseMoveEvent(self, event):
        if self.offset is not None:
            self.move(self.pos() - self.offset + event.pos())
    def mousePressEvent(self, event):
        a =  event.button()
        print(a)
        if a == Qt.RightButton:
            self.hide()
        if a == Qt.MiddleButton:
            import sys
            sys.exit(0)
        if a == Qt.LeftButton:                    
            self.offset = event.pos()
   
    def mouseReleaseEvent(self, event):
        a =  event.button()
        if a == Qt.LeftButton:
            self.offset = None
            
    def get_text(self):
        if cmd_mode:
            return 'C'
        if set_mode:
            return "S"
        
        x, y = getp()
        sx, sy = fix_pos
        dx = x - sx
        dy = y - sy
        
        if isShow:
            ss = '▲'
        elif show_one_on:
            ss = '️♥'
            if not w2.isshowing:
                ss = '■'
        else:
            ss = '♡'
            if not always_show_one:
                ss = '▽'
                '△'
        if force_show:
            ss += 'F'
        lo = '↹'
        if not lock:
            lo = ''
        st = ' %s%s %s↻ (%s)%s %s' % ('{:2s}'.format(sum), get_arr(dx,dy),sca_l[sca % len(sca_l)], lock_get(), lo,ss)
        if is_pressed:
            st += '╩'
        if mouse_is_moving:
            st += '→'
        elif not mouse_moving_last_is_fast:
            st += '↓'
        else:
            st += '↑'
        
        return st
    
    def ont(self):        
        global pause_move, move_to_win
        cur = get_cur_pos()
        sign =  (isShow, fix_pos, cur, sum,sca, sca_du, sca_cur, sca_cur_pos, lock, lock_step, pause_key,
                 pause_move, is_pressed, move_to_win, cmd_mode, set_mode, show_one_on, mouse_is_moving,
                 mouse_moving_last_is_fast, always_show_one, force_show, w2.isshowing)
        if self.last == sign:
            return
        if move_to_win:
            move_to_win = False
            geo = self.geometry()
            mouse.Controller().position = (geo.x(), geo.y())
        if self.p != pause_key:
            print('pp')
            self.p = pause_key
            if self.isHidden():
                self.setIni()
            else:
                self.hide()
                        
        if pause_move:
            self.move(pause_move[0], pause_move[1])
            self.setIni()
            pause_move = False
            
        self.last = sign
        st = self.get_text()
        
        if self.t == st:
            return
        if change_win_color:
            if '■' in st:
                self.l.setStyleSheet("QLabel {border: %spx solid rgb(0, 0, 0); background-color : rgb(0, 255, 0);  }" % main_win_border);
            else:
                self.l.setStyleSheet("QLabel {border: %spx solid rgb(0, 0, 0); background-color : white;  }" % main_win_border);
        self.t = st
        self.l.setText(st)
        f = QFont("Times", main_win_txt_size);
        f.setBold(True)
        self.l.setFont(f);                          

qq = None
def handle_event(e): #: winrawin.RawInputEvent
    if str(e.name)=='thumb1' and str(e.code)=='4':
        if str(e.event_type)=='up':
            qq.put(( 't1up',0,0,0,0))
        else:
            qq.put(( 't1down',0,0,0,0))
    if str(e.name)=='thumb2' and str(e.code)=='5':
        if str(e.event_type)=='up':
            qq.put(( 't2up',0,0,0,0))
        else:
            qq.put(( 't2down',0,0,0,0))

    if e.event_type == 'move':
        qq.put(( 'm', e.device.handle, e.delta_x, e.delta_y, time.time()))
    if e.event_type == 'wheel-up':
        qq.put(( 'w', e.device.handle, int(e.code), e.delta_y, time.time()))
    if e.event_type == 'wheel-down':
        qq.put(( 'w', e.device.handle, -int(e.code), e.delta_y, time.time())) 
    
import multiprocessing as mp        
def foo(q):
    global qq
    qq = q
    import winrawin
    import tkinter as tk    
    window = tk.Tk()
    window.maxsize(50, 50)
    winrawin.hook_raw_input_for_window(window.winfo_id(), handle_event)
    window.mainloop()
    

thrLock = threading.Lock()
mouse_q = deque()

def can_jump():
    if isShow or show_one_on:
        return False
    return True

left_mouse = []
right_mouse = []

def add_mouse(h):
    if len(left_mouse) == 0:
        left_mouse.append(h)
        print('add mouse', left_mouse, right_mouse)
    if h in left_mouse:
        return
    if h in right_mouse:
        return
    right_mouse.append(h)
    print('add mouse', left_mouse, right_mouse)
left_mouse_time = 0    
right_mouse_time = 0    
def do_mouse_jump(h):
    global left_mouse_time, right_mouse_time
    add_mouse(h)
    if h in left_mouse:
        left_mouse_time = time.time()
    if h in right_mouse:
        right_mouse_time = time.time()
        
    a = can_jump()
    #print(a)
def jump_bg():
    co = 0
    while True:
        time.sleep(0.05)
        if time.time() - left_mouse_time < 0.05 and can_jump() and time.time() - right_mouse_time < 0.3:
            co += 1
            l = [[1, 1], [1, -1], [-1, 1], [-1, -1]]
            x, y = l[co%4]
            d = 10
            x = d * x
            y = d * y
            mouse.Controller().move(x, y)
    
import queue
gq = queue.Queue()

def one_loop():
    dx1 = 0
    dy1 = 0
    dx2 =0
    dy2 = 0    
    while not gq.empty():               
        a = gq.get()        
        h, x, y, t = a
        if h in left_mouse:
            dx1 += x
            dy1 += y
        else:
            dx2 += x
            dy2 += y
    return dx1, dy1, dx2, dy2

to = 0
co = 0
def aa2(a):
    global to , co
    co += 1
    x1, y1, x2, y2 = a
    xx = x1 + x2
    yy = y1 + y2
    d3 = math.sqrt(xx * xx + yy * yy)
    d1 = math.sqrt(x1 * x1 + y1 * y1)
    d2 = math.sqrt(x2 * x2 + y2 * y2)
    du = math.atan2(y1, x1)
    du2 = math.atan2(y2, x2)
    d = du2 - du
    if d >  math.pi:
        d -= 2 * math.pi
    if d < - math.pi:
        d += 2 * math.pi   
    
    if d3 > max(d2 , d1):
        return
    
    if d1 < 1 or d2 < 1:
        return
        
    if abs(d) < math.pi * 0.5:
        return
    
    a = -1
    
    if abs(x2) > abs(y2):
        if x2 > 0:
            a = 1
    else:
        if y2 > 0:
            a = 1    
    return a * max(d1, d2)


to_time = 0
def thrf():
    global  is_moving, start_t , last_move_time, gdx, gdy, g_m, to, to_time,to_change_time
    q = deque([], maxlen=3)
    while True:
        time.sleep(0.05)
        a = one_loop()       
        dd = aa2(a)       
        if dd == None:
            continue
        if (to <= 0 and dd < 0) or (to >= max_l and dd > 0):
            continue
        to_lock.acquire()        
        to = cut_to(to+dd*30)
        to_time = time.time()
        to_change_time = time.time()
        to_lock.release()        
        print('to',to )
force_scroll = False

if __name__ == '__main__':
    jumpT = threading.Thread(target=jump_bg)
    jumpT.daemon = True
    jumpT.start()
    thrb = threading.Thread(target=thrf)
    thrb.daemon = True
    thrb.start()
    
    mouse_listener = mouse.Listener(on_move=on_move,on_click=on_click)
    mouse_listener.start()        
    moveT = threading.Thread(target=moveF)
    moveT.daemon = True
    moveT.start()
    load_pos()
    listener = keyboard.Listener(
        on_release=on_release,
        on_press=on_press,
    )
    
    listener.start()        
    app = QApplication([])   
    w2 = my77()
    w3 = my3()
    
    q = mp.Queue()
    if listen_mouse_click:
        p = mp.Process(target=foo, args=(q,))
        p.daemon = True
        p.start()
        print('pid', os.getpid(), p.pid)
    
    def aa():
        global enter_pressed_then_other,x2_pressed_then_other,to,to_change_time
        while True:
            aa = q.get()
            ty, a, x, y, t = aa
            if ty=='t1up':
                on_click2(0,0,'x1',False,True)
                continue
            if ty=='t1down':
                on_click2(0,0,'x1',True,True)
                continue
            if ty=='t2up':
                on_click2(0,0,'x2',False,True)
                continue
            if ty=='t2down':
                on_click2(0,0,'x2',True,True)
                continue

            if ty == 'w':
                if str(a) == 'None':
                    continue
                if not w2.isshowing:
                    continue
                if force_scroll:
                    continue
                if enter_pressed:
                    enter_pressed_then_other = True
                    continue
                if x2_pressed:
                    x2_pressed_then_other = True
                    continue
                to_lock.acquire()
                
                if x > 0:
                    to = cut_to(to+get_scroll_sca())                    
                else:
                    to = cut_to(to-get_scroll_sca())                    
                to_change_time = time.time()
                to_lock.release()
                
                mouse.Controller().scroll(0, -x//2)                    
                continue
            
            aa = (a, x, y, t)
            gq.put(aa)
            do_mouse_jump(a)                       
            thrLock.acquire()
            while len(mouse_q) > 0:
                t, h = mouse_q[0]
                if time.time() - t < two_mouse_check_interval:
                    break
                mouse_q.popleft()
            mouse_q.append((time.time(), a))
            thrLock.release()
            
    tt = threading.Thread(target=aa)
    tt.daemon = True
    tt.start()
        
    app.exec_()        